package de.servicezombie.tests.spring;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import de.servicezombie.tests.mongo.MongoTestSupport;

public class SpringTemplate {

	private static final Logger log = LoggerFactory.getLogger(SpringTemplate.class);
	
	private ApplicationContext applicationContext;
	private MongoTestSupport mongoTestSupport;
	
	public void setMongoTestSupport(MongoTestSupport mongoTestSupport) {
		this.mongoTestSupport = mongoTestSupport;
	}

	protected SpringTemplate(BeanFactory beanFactory) {
		this.applicationContext = new BeanFactoryOnlyApplicationContext(beanFactory);
	}

	protected SpringTemplate(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		
		int count = this.applicationContext.getBeanNamesForType(MongoTestSupport.class).length;
		if(count == 1) {
			log.info("configure db support for mongo db");
			this.mongoTestSupport = applicationContext.getBean(MongoTestSupport.class);
		}
		else {
			log.info("no mongo support available. need eaxctly 1 instance of " + MongoTestSupport.class.getName() + ", found " + count);
		}
	}

	@SuppressWarnings("unchecked")
	public final <T> T getBean(String name) {
		T bean = (T) applicationContext.getBean(name);

		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(applicationContext);
		}

		return bean;
	}

	public final void autowireByName(Object targetBean) {

		// throws exception, why?
		PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(targetBean.getClass());

		for (PropertyDescriptor pd : propertyDescriptors) {
			Method writeMethod = pd.getWriteMethod();
			if (writeMethod != null) {
				String name = pd.getName();
				Object bean = getBean(name);
				try {
					writeMethod.invoke(targetBean, bean);
				}
				catch (Exception e) {
					throw new BeanCreationException("unable to wire property " + name + ": " + e.getMessage(), e);
				}
			}
		}

	}


	public void rebuildDatabase(Class<?>... types) {
		mongoTestSupport.rebuildDatabase(types);		
	}

}
